package com.gitee.limaozhi.socket.lesson03.example3;

import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 输出处理器
 *
 * @author hzlimaozhi
 * @date 2019/08/07 11:38
 */
public class OutputHandler extends HandlerAdapter {

    private int prevReq = -1;
    private AtomicInteger req = new AtomicInteger(0);
    private boolean fireFinish = false;

    private LinkedBlockingQueue<byte[]> queue = new LinkedBlockingQueue<>();
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public Handler handle(Object object) {
        context().execute(() -> {
            try {
                queue.put((byte[]) object);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return;
            }

            // 最多只有一个线程
            if (lock.tryLock()) {
                try {
                    while (true) {
                        byte[] item = queue.poll();
                        if (item == null) {
                            break;
                        }
                        try {
                            context().getOutputStream().write(item);
                        } catch (IOException e) {
                            System.out.println(context().getName() + "异常：");
                            e.printStackTrace();
                        }
                        req.incrementAndGet();
                        fireFinish();
                    }
                } finally {
                    lock.unlock();
                }
            }
//            context().print(context().getName() + "：Output：线程退出");
        });
        return this;
    }

    @Override
    public Handler finish(int prevReq) {
        this.prevReq = prevReq;
        // 如果finish比较晚，则在此触发
        fireFinish();
        return this;
    }

    private synchronized void fireFinish() {
        if (!fireFinish) {
            if (prevReq == req.get()) {
                fireFinish = true;
//                context().print(context().getName() + "：Output：" + req.get());
                context().shutdownOutput();
            }
        }
    }

}
